
    avalon.scan = function(elem, vmodel) {
        elem = elem || root
        var vmodels = vmodel ? [].concat(vmodel) : []
        scanTag(elem, vmodels)
    }

    function scanNodes(parent, vmodels, callback) {
        var nodes = []
        for (var i = 0, node; node = parent.childNodes[i++]; ) {
            nodes.push(node);
        }
        callback && callback();
        for (var i = 0; node = nodes[i++]; ) {
            if (node.nodeType === 1) {
                scanTag(node, vmodels) //扫描元素节点
            } else if (node.nodeType === 3) {
                scanText(node, vmodels) //扫描文本节点
            }
        }
    }

    var stopScan = avalon.oneObject("area,base,basefont,br,col,hr,img,input,link,meta,param,embed,wbr,script,style,textarea")


    function scanTag(elem, vmodels) {
        vmodels = vmodels || []
        var a = elem.getAttribute(prefix + "skip")
        var b = elem.getAttribute(prefix + "important")
        var c = elem.getAttribute(prefix + "controller")

        //这三个绑定优先处理，其中a > b > c
        if (typeof a === "string") {
            return
        } else if (b) {
            if (!VMODELS[b]) {
                return
            } else {
                vmodels = [VMODELS[b]]
                elem.removeAttribute(prefix + "important")
            }
        } else if (c) {
            var newVmodel = VMODELS[c]
            if (!newVmodel) {
                return
            }
            vmodels = [newVmodel].concat(vmodels)
            elem.removeAttribute(prefix + "controller")
        }
        scanAttr(elem, vmodels) //扫描特性节点
        if (!stopScan[elem.tagName] && rbind.test(elem.innerHTML)) {
            scanNodes(elem, vmodels)
        }
    }

    function scanText(textNode, vmodels) {
        var bindings = extractTextBindings(textNode)
        if (bindings.length) {
            executeBindings(bindings, vmodels)
        }
    }

    var rfilters = /[^|]\|\s*(\w+)\s*(\([^)]*\))?/g

    function scanExpr(value) {
        var tokens = [],
                left
        if (rexpr.test(value)) {
            do {
                value.replace(rexpr, function(a, b) {
                    left = RegExp.leftContext
                    value = RegExp.rightContext
                    if (left) {
                        tokens.push({
                            value: left,
                            expr: false
                        })
                    }
                    if (b) {
                        var leach = []
                        if (b.indexOf("|") > 0) { // 注意排除短路与
                            b = b.replace(rfilters, function(c, d, e) {
                                leach.push(d + (e || ""))
                                return c.charAt(0)
                            })
                        }
                        tokens.push({
                            value: b,
                            expr: true,
                            filters: leach.length ? leach : void 0
                        })

                    }
                    return ""
                });
            } while (value.indexOf(closeTag) > -1);

            if (value) {
                tokens.push({
                    value: value,
                    expr: false
                })
            }
        }

        return tokens
    }


    function scanAttr(el, vmodels) {
        var bindings = []
        for (var i = 0, attr; attr = el.attributes[i++]; ) {
            if (attr.specified) {
                var isBinding = false
                if (attr.name.indexOf(prefix) !== -1) {
                    //如果是以指定前缀命名的
                    var type = attr.name.replace(prefix, "")
                    if (type.indexOf("-") > 0) { //如果还指定了参数
                        var args = type.split("-")
                        type = args.shift()
                    }
                    isBinding = typeof bindingHandlers[type] === "function"
                } else if (rexpr.test(attr.value)) {
                    type = isBinding = "attr"
                }
                if (isBinding) {
                    bindings.push({
                        type: type,
                        args: args || [],
                        element: el,
                        remove: true,
                        node: attr,
                        value: attr.nodeValue
                    })
                }
            }
        }
        executeBindings(bindings, vmodels)
    }

    function executeBindings(bindings, vmodels) {
        bindings.forEach(function(data) {
            bindingHandlers[data.type](data, vmodels) //avalon.mix({},data)
            if (data.remove) { //移除数据绑定，防止被二次解析
                data.element.removeAttribute(data.node.name)
            }
        })
    }

    function extractTextBindings(textNode) {
        var bindings = [],
                tokens = scanExpr(textNode.nodeValue)
        if (tokens.length) {
            while (tokens.length) { //将文本转换为文本节点，并替换原来的文本节点
                var token = tokens.shift()
                var node = DOC.createTextNode(token.value)
                if (token.expr) {
                    var filters = token.filters
                    var binding = {
                        type: "text",
                        node: node,
                        args: [],
                        element: textNode.parentNode,
                        value: token.value,
                        filters: filters
                    }
                    if (filters && filters.indexOf("html") !== -1) {
                        avalon.Array.remove(filters, "html")
                        binding.type = "html"
                        binding.replaceNodes = [node]
                    }
                    bindings.push(binding) //收集带有插值表达式的文本
                }
                documentFragment.appendChild(node)
            }
            textNode.parentNode.replaceChild(documentFragment, textNode)
        }
        return bindings
    }

    